package com.wyj.executor;

import com.wyj.config.BoundSql;
import com.wyj.pojo.Configuration;
import com.wyj.pojo.MapperedStatement;
import com.wyj.utils.ParameterMapping;
import org.apache.log4j.Logger;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author wuyijie
 * @description: TODO 具体jdbc的实现
 * @date 2021/10/30 2:42 下午
 */
public class SimpleExecutor implements Executor {
    private static final Logger LOGGER = Logger.getLogger(SimpleExecutor.class);

    /**
     * 基本类型、包装类型、String类型
     */
    private static final Map<String, String> DEFAULT_TYPE_MAP = new HashMap<>();

    static {
        DEFAULT_TYPE_MAP.put("java.lang.Integer", "int");
        DEFAULT_TYPE_MAP.put("java.lang.Double", "double");
        DEFAULT_TYPE_MAP.put("java.lang.Long", "long");
        DEFAULT_TYPE_MAP.put("java.lang.Short", "short");
        DEFAULT_TYPE_MAP.put("java.lang.Byte", "byte");
        DEFAULT_TYPE_MAP.put("java.lang.Boolean", "boolean");
        DEFAULT_TYPE_MAP.put("java.lang.Character", "char");
        DEFAULT_TYPE_MAP.put("java.lang.Float", "float");

    }

    @Override
    public <E> List<E> query(Configuration configuration, MapperedStatement mapperedStatement, Object... params) throws SQLException, ClassNotFoundException, NoSuchFieldException {
        List<Object> resultList = new ArrayList<>();
        //1、获取jdbc连接
        Connection connection = configuration.getDataSource().getConnection();

        //2、获取sql--转换sql，将#{}替换为？
        // String sql = mapperedStatement.getSql();
        BoundSql boundSql = mapperedStatement.getBoundSql();

        //3、获取jdbc预处理对象
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());

        //4、参数赋值。获取参数的clazz
        Class<?> parameterType = mapperedStatement.getParameterType();
        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();

        for (int i = 0; i < parameterMappingList.size(); i++) {
            String content = parameterMappingList.get(i).getContent();
            Field field = parameterType.getDeclaredField(content);
            field.setAccessible(true);
            Object fieldValue;
            try {
                Object param = params[0];
                fieldValue = field.get(param);
                //为预处理语句参数赋值。从1开始
                preparedStatement.setObject(i + 1, fieldValue);
            } catch (IllegalAccessException e) {
                LOGGER.error("query error ", e);
                throw new IllegalAccessError();
            }
        }

        //5、执行sql
        ResultSet resultSet = preparedStatement.executeQuery();

        //6、封装返回结果
        Class<?> resultTypeClazz = mapperedStatement.getResultType();

        while (resultSet.next()) {
            Object result = null;
            try {
                result = resultTypeClazz.getDeclaredConstructor().newInstance();
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                LOGGER.error("query error ", e);
            }
            //查询结果元数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                //字段名
                String fieldName = metaData.getColumnName(i);
                //字段值
                Object fieldValue = resultSet.getObject(i);
                try {
                    //Java内省相关类
                    PropertyDescriptor propertyDescriptor = new PropertyDescriptor(fieldName, resultTypeClazz);
                    Method writeMethod = propertyDescriptor.getWriteMethod();
                    writeMethod.invoke(result, fieldValue);

                    //通过暴力破解，反射赋值
                    // Field field = resultTypeClazz.getField(fieldName);
                    // field.setAccessible(true);
                    // field.set(result,fieldValue);
                } catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) {
                    LOGGER.error("query error ", e);
                }
            }
            resultList.add(result);
        }
        @SuppressWarnings("unchecked")
        List<E> resultList1 = (List<E>) resultList;
        return resultList1;
    }

    @Override
    public int update(Configuration configuration, MapperedStatement mapperedStatement, Object... params) throws SQLException, ClassNotFoundException, NoSuchFieldException {
        int updateCount = 0;
        //1、获取jdbc连接
        Connection connection = configuration.getDataSource().getConnection();

        //2、获取sql--转换sql，将#{}替换为？
        // String sql = mapperedStatement.getSql();
        BoundSql boundSql = mapperedStatement.getBoundSql();

        //3、获取jdbc预处理对象
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());

        //4、参数赋值。获取参数的clazz
        Class<?> parameterType = mapperedStatement.getParameterType();


        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();

        for (int i = 0; i < parameterMappingList.size(); i++) {
            String content = parameterMappingList.get(i).getContent();
            if (isSimpleType(parameterType)) {
                preparedStatement.setObject(i + 1, params[i]);
            } else {
                Field field = parameterType.getDeclaredField(content);
                field.setAccessible(true);
                Object fieldValue;
                try {
                    Object param = params[0];
                    fieldValue = field.get(param);
                    //为预处理语句参数赋值。从1开始
                    preparedStatement.setObject(i + 1, fieldValue);
                } catch (IllegalAccessException e) {
                    LOGGER.error("query error  ", e);
                    throw new IllegalAccessError();
                }
            }

        }

        //5、执行sql
        int resultSet = preparedStatement.executeUpdate();

        //6、封装返回结果
        updateCount = preparedStatement.getUpdateCount();
        System.out.println("resultset=" + resultSet + ", updatecount=" + updateCount);
        return updateCount;
    }

    private boolean isSimpleType(Class<?> parameterType) {
        return DEFAULT_TYPE_MAP.containsKey(parameterType.getName());
    }

}
